#!/usr/bin/env python
#
# Common writer mechanism for grid map files, job traces, and any other
# files in similar formats.
#
# Author:   Mike Murphy <mamurph@cs.clemson.edu>
# Revision: 23 September 2009
#
#   Copyright 2009 Clemson University
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
# This material is based upon work supported under a National Science
# Foundation Graduate Research Fellowship. Any opinions, findings,
# conclusions or recommendations expressed in this publication are those of
# the author(s) and do not necessarily reflect the views of the National
# Science Foundation.

'''
Common writer mechanism for simulator input formats (map, job trace, etc.).
'''

import time

class CommonWriter(object):
   def __init__(self, fh, fmt_num, header, normalize_time=False):
      '''
      @param fh: Open file handle (w mode) to which output is written
      @param fmt_num: File format number
      @type fmt_num: float
      @param header: Header line to be placed in the comment at the top of
                     the output file
      @type header: str
      @param normalize_time: flag to specify whether timestamps will be
                             written as offsets from the first written time
                             (which will be written as zero in the file)
      @type normalize_time: bool
      '''
      self.first_timestamp = -1
      self.previous_actual = -1
      self.offset_mode = normalize_time
      self.fh = fh
      fh.write('# %s\n\n' % header)
      fh.write('format %s\n' % str(fmt_num))
      fh.write('version %s\n\n' % str(time.time()))
   def write_time(self, timeval, is_offset=False):
      '''
      Writes a clock timestamp to the output file, after which a record may
      be written.

      @param timeval: Timestamp value to write
      @type timeval: number
      @param is_offset: indicates whether or not timeval is an offset from the
                        previous timestamp. If False, timeval is assumed
                        to be an absolute timestamp.
      @type is_offset: bool
      '''
      actual = 0
      offset = 0
      if is_offset:
         offset = timeval
         actual = max(self.first_timestamp, 0) + offset
      else:
         actual = timeval
         offset = actual - self.first_timestamp
         if self.first_timestamp < 0:
            offset = 0
      if actual < self.previous_actual:
         raise Exception('Timestamp earlier than previous timestamp')
      if self.first_timestamp < 0:
         if self.offset_mode:
            self.fh.write('epoch %s\n' % str(actual))
         else:
            self.fh.write('epoch 0\n')
         self.first_timestamp = actual
      self.previous_actual = actual
      wr_str = str(actual)
      if self.offset_mode:
         wr_str = str(offset)
      self.fh.write('\nclock %s\n' % wr_str)
   def write_meta(self, name, value):
      '''
      Writes a single metadata record to the output file handle

      @param name: Name of metadata item
      @type name: str
      @param value: Value of metadata item (will be cast to str)
      '''
      self.fh.write('meta %s = %s\n' % (str(name), str(value)))
   def write_meta_comment(self, comment):
      '''
      Writes a metadata comment to the output file handle. This type of
      comment is used to describe information about the contents of the file.

      @param comment: comment to write as metadata
      @type comment: str
      '''
      self.fh.write('meta comment = %s\n' % comment)
   def write_line_comment(self, comment):
      '''
      Writes a line comment to the output file handle. Line comments are
      literal file comments (starting with the "#" symbol) and are useful
      for debugging automated file production/conversion tools.

      @param comment: string to write as a file comment
      @type comment: str
      '''
      self.fh.write('# %s\n' % comment)
   def write_blank(self):
      '''
      Writes a blank line to the output file handle
      '''
      self.fh.write('\n')
   def check_time(self):
      '''
      Ensures that a call to write_time has been performed. If write_time
      has not yet been called, an Exception is raised.
      '''
      if self.first_timestamp < 0:
         raise Exception('Timestamp must be written before first record')
#
